﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace yCloud
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    public class YCloudService : IYCloudService
    {
        private yCloudEntities entities;
        public YCloudService()
        {
            this.entities = new yCloudEntities();
        }

        public int MakeFolder(string name, int parentId = 0)
        {
            bool parentExists = parentId == 0 || entities.Folders.Where(f => f.ID == parentId).FirstOrDefault() != null;
            if (parentExists)
            {
                if (parentId == 0)
                {
                    //Adding a folder to the root
                    bool folderAlreadyExists = entities.Folders.Where(f => !f.ParentID.HasValue && f.Name == name).FirstOrDefault() != null;
                    if (folderAlreadyExists)
                    {
                        return 0;
                    }
                    Folder folder = new Folder();
                    folder.Name = name;
                    entities.Folders.AddObject(folder);
                    entities.SaveChanges();
                    return folder.ID;
                }
                else
                {
                    //Adding a folder to another folder
                    bool folderAlreadyExists = entities.Folders.Where(f => (f.ParentID ?? 0) == parentId && f.Name == name).FirstOrDefault() != null;
                    if (folderAlreadyExists)
                        return 0;
                    Folder folder = new Folder();
                    folder.Name = name;
                    folder.ParentID = parentId;
                    entities.Folders.AddObject(folder);
                    entities.SaveChanges();
                    return folder.ID;
                }
            }
            else
            {
                return -1;
            }
        }

        public void DeleteFolder(int folderId)
        {
            Folder toDelete = entities.Folders.Where(f => f.ID == folderId).FirstOrDefault();
            if (toDelete != null)
            {
                foreach (File file in toDelete.Files.ToArray())
                {
                    entities.Files.DeleteObject(file);
                }
                foreach (Folder folder in toDelete.Children.ToArray())
                {
                    this.RecursivelyDeleteSubItems(folder);
                    entities.Folders.DeleteObject(folder);
                }
                entities.Folders.DeleteObject(toDelete);
                entities.SaveChanges();
            }
        }

        private void RecursivelyDeleteSubItems(Folder folder)
        {
            foreach (File file in folder.Files.ToArray())
            {
                entities.Files.DeleteObject(file);
            }
            foreach (Folder subFolder in folder.Children.ToArray())
            {
                RecursivelyDeleteSubItems(subFolder);
            }
        }

        public int UploadFile(byte[] fileData, string fileName, int parentFolder = 0)
        {
            Folder folder = entities.Folders.Where(f => f.ID == parentFolder).FirstOrDefault();
            if (folder == null && parentFolder != 0)
                return -1;
            else
            {
                bool fileAlreadyExists = (parentFolder == 0 && entities.Files.Where(f => !f.Folder.HasValue && f.Name == fileName).FirstOrDefault() != null) || (folder != null && folder.Files.Where(f => f.Name == fileName).FirstOrDefault() != null);
                if (fileAlreadyExists)
                    return 0;
                else
                {
                    File newFile = new File();
                    newFile.Name = fileName;
                    if(parentFolder != 0)
                        newFile.Folder = parentFolder;
                    newFile.Data = fileData;
                    entities.Files.AddObject(newFile);
                    entities.SaveChanges();
                    return newFile.ID;
                }
            }
        }

        public void UpdateFileContent(int fileId, byte[] fileData)
        {
            File file = entities.Files.Where(f => f.ID == fileId).FirstOrDefault();
            if (file == null)
            {
                throw new ArgumentException("The file id provided does not exist");
            }
            else
            {
                file.Data = fileData;
                entities.SaveChanges();
            }
        }

        public void UpdateFileInfo(int fileId, string fileName)
        {
            File file = entities.Files.Where(f => f.ID == fileId).FirstOrDefault();
            if (file == null)
            {
                throw new ArgumentException("The file id provided does not exist");
            }
            bool fileAlreadyExists = file.ParentFolder != null ? file.ParentFolder.Children.Where(f => f.Name == fileName).FirstOrDefault() != null : entities.Files.Where(f => f.ParentFolder == null && f.Name == fileName).FirstOrDefault() != null;
            if (fileAlreadyExists)
                throw new ArgumentException("There is already a file with this name in the new directory");
            file.Name = fileName;
            entities.SaveChanges();
        }

        public void DeleteFile(int fileId)
        {
            File file = entities.Files.Where(f => f.ID == fileId).FirstOrDefault();
            if (file != null)
            {
                entities.DeleteObject(file);
                entities.SaveChanges();
            }
        }

        public SerializableFolder GetFolder(int folderId)
        {
            if (folderId == 0)
            {
                //The client is asking for the root folder
                int[] filesUnderRoot = entities.Files.Where(f => !f.Folder.HasValue).Select(f => f.ID).ToArray();
                int[] foldersUnderRoot = entities.Folders.Where(f => !f.ParentID.HasValue).Select(f => f.ID).ToArray();
                SerializableFolder root = new SerializableFolder();
                root.Files = filesUnderRoot;
                root.SubFolders = foldersUnderRoot;
                root.Name = "Root";
                return root;
            }
            else
            {
                Folder folder = entities.Folders.Where(f => f.ID == folderId).FirstOrDefault();
                if (folder == null)
                    return null;
                else
                {
                    SerializableFolder sFolder = new SerializableFolder();
                    sFolder.Populate(folder);
                    return sFolder;
                }
            }
        }

        public SerializableFile GetFile(int fileId)
        {
            File file = entities.Files.Where(f => f.ID == fileId).FirstOrDefault();
            if (file == null)
                return null;
            else
            {
                SerializableFile sFile = new SerializableFile();
                sFile.Populate(file);
                return sFile;
            }
        }

        public SerializableFile GetFileWithoutData(int fileId)
        {
            SerializableFile file = GetFile(fileId);
            if (file == null)
                return null;
            file.Content = null;
            return file;
        }

        public void RenameFolder(int folderId, string folderName)
        {
            Folder folder = entities.Folders.Where(f => f.ID == folderId).FirstOrDefault();
            if (folder == null)
                throw new ArgumentException("A Folder with this ID does not exist");
            Folder folderWithThisName = folder.Parent != null ? folder.Parent.Children.Where(c => c.Name == folderName).FirstOrDefault() : entities.Folders.Where(f => f.Parent == null && f.Name == folderName).FirstOrDefault();
            if (folderWithThisName != null)
                throw new ArgumentException("There already exists a folder with this name");
            folder.Name = folderName;
            entities.SaveChanges();
        }
    }
}
